﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Collections;
using System.IO.Ports;


namespace my_rs232
{
    public partial class Form1 : Form

    {
        public string[] SerialPort_str= new string[5];
        public string[] Rs232_str= new string[100];
        public string[] tooltip_str= new string[100];
        public bool [] visible_str = new bool [100];
        public string inifilename;
        public int but_con;
        public bool OnWatch = false;
        int mykey;

        

        public enum LogMsgType { Incoming, Outgoing, Normal, Warning, Error };
        

        public Form1(int key)
        {
            inifilename = "232.ini";
            but_con = 0;
            mykey = key;
            InitializeComponent();


        }

        private void Form1_Load(object sender, EventArgs e)
        {

            RS232_reset();
            if (mykey == 1)
            {
                //如果接受参数是1，发送关闭信号并退出程序，最后需要取消注销
                SendData(Rs232_str[1]);
                this.Close();
            }

            SendData(Rs232_str[0]);
        }
        private void RS232_reset()
        {
            lokal_seting();
            setbut();
            setHeight();
            setrfttop();

        }
          

        //动态添加按钮，设置布局，text，name，鼠标悬浮标签
        private ArrayList Read_txt()
        {
            //读取本地txt文件返回string数组 //是文件中的注释行不会被读取
            ArrayList str = new ArrayList();
            //Encoding.Default制定默认编码可以读取中文
            StreamReader objReader = new StreamReader(inifilename, Encoding.Default);
            string sLine = "";
            while (sLine != null)
            {
                sLine = objReader.ReadLine();
                if (sLine != null && !sLine.Equals(""))
                {

                    //rs[i] = sLine;
                    str.Add(sLine);
                }
            }
            objReader.Close();
            return str;
            //string[] arrString = (string[])str.ToArray(typeof(string));
            //return arrString;
        }
        private void lokal_seting()
        {
            bool serialport=true;
            int i = 0;
            //从本地TXT读取信息到ArrayList readtxt
            ArrayList readtxt=Read_txt();
            foreach (object obj in readtxt)
             {
                string ReadTxtline= (string)obj;
                //去除注释
                if(ReadTxtline[0]!='/')
                {
                    //判读是端口设置还是串口信号设置
                    if (ReadTxtline[0] == '#') 
                    {
                        serialport = false;
                        i=0;
                    }
                    if (serialport )
                    {
                        //在读取的一行中使用%分割为数组
                        string[] rs = ReadTxtline.Split('%');
                        if (rs[0] != null)
                        {
                            SerialPort_str[i] = rs[0];
                            i = i + 1;
                        }

                    }else{
                        if( ReadTxtline[0] != '#')
                        {
                        //在读取的一行中使用%分割为数组
                        string[] rs = ReadTxtline.Split('%');
                        if (rs.Length == 1)
                        {
                            Rs232_str[i] = rs[0];
                            i = i + 1;
                        }
                        else
                        {
                            if (rs[0] != null)
                            {
                                visible_str[i] = bool.Parse(rs[0]);
                               if(visible_str[i]) but_con = but_con + 1;
                            }
                            if (rs[1] != null) Rs232_str[i] = rs[1];
                            if (rs[2] != null) tooltip_str[i] = rs[2];
                            i = i + 1;
                        }
                        }

                    }
                }
             }

        }
        private void setbut()
        {
            //根据读取的配置文件的到数组动态添加but，并绑定事件
            try
            {
                for (int i = 0; i < but_con; i++)
                {
                    Button bt = new Button();
                    //设定位置
                    bt.Height = 25;
                    bt.Width = 100;
                    bt.Left = 10 + (i % 3) * 102;
                    bt.Top = 40 + (i / 3) * 27;
                    bt.Name = "butgroup" + (i + 10);
                    bt.Text = tooltip_str[i];
                    bt.Tag = i;
                    //bt.Click = butgrup_click;
                     
                    bt.MouseClick +=new MouseEventHandler(butgroup_click);
                    toolTip1.SetToolTip(bt, Rs232_str[i]);

                    //添加控件
                    this.Controls.Add(bt);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message); ;
            }
        }
        private void butgroup_click(object sender, EventArgs e)
        {
            //根据获取but的tag值发送不同的串号
            Button button = sender as Button;
            if (button == null) return;
            int i = (int)button.Tag;
            SendData(Rs232_str[i]);
        }
        private void setHeight()
        {
            //设置窗口高度
            this.Height =110 + (but_con / 3) * 27;
        }
        private void setrfttop()
        {
            //设置监视窗口位置
            rtfTerminal.Top = 80 + (but_con / 3) * 27;
        }

        //初始化端口
        private void InitSeriaPort()
        {
            //开启COM口
            if (comport.IsOpen) comport.Close();
            else
            {
                //根据本地系统设置，打开通信端口
                //设置比特率
                comport.BaudRate = Convert.ToInt32(SerialPort_str[0]);
                //设置每个字节的标准数据位长度
                comport.DataBits = Convert.ToInt32(SerialPort_str[1]);
                //设置每个字节的标准停止位数
                //comport.StopBits = Settings.Default.StopBits;
                //设置奇偶校验协议
                //comport.Parity = Settings.Default.Parity;
                //设置通信端口
                comport.PortName = SerialPort_str[2];


                //开启通信端口
                if (CheckCom(SerialPort_str[2])) comport.Open();
                else
                {
                    Log(LogMsgType.Outgoing, "端口设置错误，或者您的计算机就没有COM端口");

                }

                //启动控制按钮
                //EnbleControls();

                if (comport.IsOpen)
                {
                    //向日志发送信息
                    Log(LogMsgType.Outgoing, "通信端口开启");
                }
            }
        }

        //关闭端口
        private void CloseSeriaPort()
        {
            if (comport.IsOpen) comport.Close();
            Log(LogMsgType.Outgoing, "通信端口关闭");
        }
        //发送数据
        private void SendData(string sendstr)
        {//去不使用16进制控制信号

            //启动端口
            InitSeriaPort();

            //以string的形式得到十六进制的序列
            byte[] data = HexStringToByteArray(sendstr);
            // 发送有十六进制得到序列转好成的二进制序列
            if (CheckCom(SerialPort_str[2]))
            {
                comport.Write(data, 0, data.Length);
                Log(LogMsgType.Outgoing, ByteArrayToHexString(data) + "发送完成");
            }
            else
            {
                Log(LogMsgType.Outgoing, "端口设置错误，或者您的计算机就没有COM端口");
            }

            //关闭端口
            CloseSeriaPort();
        }

        private bool CheckCom(string ComName)
        {
            bool HaveCOM;
            HaveCOM = false;
            foreach (string s in SerialPort.GetPortNames())
                if (s == ComName) HaveCOM = true;
            return HaveCOM;
        }

        private byte[] HexStringToByteArray(string s)
        {
            //十六进制转byte
            s = s.Replace(" ", "");
            double str_up_length;
            double s_length;
            s_length = s.Length;
            str_up_length = Math.Ceiling(s_length / 2);
            if ((2 * str_up_length - s_length) != 0)
            {
                Log(LogMsgType.Outgoing, "16进制需要是偶数位 控制码错误");
                byte[] buffer = new byte[s.Length / 2];
                return buffer;
            }
            else
            {
                byte[] buffer = new byte[s.Length / 2];
                for (int i = 0; i < s.Length; i += 2)
                {
                    buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);
                }
                return buffer;
            }
        }

        private string ByteArrayToHexString(byte[] data)
        {
            StringBuilder sb = new StringBuilder(data.Length * 3);
            foreach (byte b in data)
                sb.Append(Convert.ToString(b, 16).PadLeft(2, '0').PadRight(3, ' '));
            return sb.ToString().ToUpper();
        }
        private void Log(LogMsgType msgtype, string msg)
        {

            //这里是引用原有作者的，我自己不太明白
            rtfTerminal.Invoke(new EventHandler(delegate
            {
                rtfTerminal.SelectedText = string.Empty;
                rtfTerminal.AppendText(msg + "\n");
                rtfTerminal.ScrollToCaret();
            }));
        }


        private void openFileDialog1_FileOk(object sender, CancelEventArgs e)
        {
            inifilename = openFileDialog1.FileName;
        }

        private void toolStripMenuItem1_Click(object sender, EventArgs e)
        {
            //选择配置文件

            openFileDialog1.ShowDialog();
            RS232_reset();
        }

        private void 监控ToolStripMenuItem_Click(object sender, EventArgs e)
        {
           //显示或者隐藏监视窗口
            if (OnWatch)
            {
                OnWatch =false;

                this.Height = this.Height - 160;
            }
            else
            {
                OnWatch = true;
                this.Height = this.Height + 160;
            }

        }

        public const int WM_QUERYENDSESSION = 0x0011; //当用户选择结束对话框或程序自己调用ExitWindows函数   

        protected override void WndProc(ref Message m)
        {
     
            switch (m.Msg)
            {
                //此消息在OnFormClosing之前
                case WM_QUERYENDSESSION:
                    SendData(Rs232_str[2]);
                    MessageBox.Show("发送关机串号后的验证信息");
                    break;
                default:
                    break;
            }
            base.WndProc(ref m);
        }

        private void 帮助ToolStripMenuItem_Click(object sender, EventArgs e)
        {
           // AutoDown autodown = new AutoDown();
           // autodown.Show();
            MessageBox.Show("感谢家人对我的关爱和支持。感谢网友的支持。\n本次是对投影机控制的第三版：\n 1.配置文件一定要严格按照配置文件的样板写，程序没有对配置文件的有效性做验证，如果配置文件格式不对，程序会出错，或者不能控制投影机。\n2.根据配置文件动态增加按钮，最多支持100个按钮。\n 3.本工具打开时自动发送投影机开机串号，如果把软件快捷方式放在启动菜单中，就可以实现电脑开机投影机自己开机。\n 4.本工具捕获WM_QUERYENDSESSION消息后发送投影机关机串号。\n 5.开机信号一定要放在第一行，关机信号一定要放在第二行。\n 6.QQ 68817033");

        }
        //C#最小化到托盘+双击托盘恢复 
        //    1.添加notifyIcon控件，并添加Icon，否则托盘没有图标（托盘右键菜单也可直接在属性里添加）；
        //    2.响应Form的Resize或SizeChanged消息：

        private void Form1_Resize(object sender, EventArgs e)
        {
            //单击最小化，进入系统托盘

            if (this.WindowState == FormWindowState.Minimized)
            {
                this.Hide();
                this.ShowInTaskbar = false;
                this.notifyIcon.Visible = true;
            }
        }

        private void notifyIcon_DoubleClick(object sender, EventArgs e)
        {
            //从系统托盘恢复窗体
            if (this.WindowState == FormWindowState.Minimized)
            {
                this.Show();
                this.WindowState = FormWindowState.Normal;
                notifyIcon.Visible = false;
                this.ShowInTaskbar = true;
            }
        }

 
    }
}
